#include "CollisionListener.h"
#include "..\Components\GameObject.h"
#include "..\Managers\GameObjectManager.h"
#include "..\Components\SensorComponent.h"
#include "..\Components\HealthComponent.h"
#include "..\Components\DamageComponent.h"
#include "..\Components\PlayerControllerComponent.h"
#include "..\EnumDefine.h"
#include <iostream>

CollisionListener::CollisionListener(void) { initCollisionMaps(); }

CollisionListener::~CollisionListener(void)
{
	m_beginContactCollisionMap.clear();
	m_endContactCollisionMap.clear(); 
}

void CollisionListener::BeginContact(b2Contact* p_contact)
{
 	auto it = m_beginContactCollisionMap.find(std::make_pair((int)p_contact->GetFixtureA()->GetUserData(), (int)p_contact->GetFixtureB()->GetUserData()));
	if (it != m_beginContactCollisionMap.end())
		(this->*it->second)(p_contact->GetFixtureA()->GetBody()->GetUserData(), p_contact->GetFixtureB()->GetBody()->GetUserData());
}

void CollisionListener::EndContact(b2Contact* p_contact)
{
	auto it = m_endContactCollisionMap.find(std::make_pair((int)p_contact->GetFixtureA()->GetUserData(), (int)p_contact->GetFixtureB()->GetUserData()));
	if (it != m_endContactCollisionMap.end())
		(this->*it->second)(p_contact->GetFixtureA()->GetBody()->GetUserData(), p_contact->GetFixtureB()->GetBody()->GetUserData());
}

inline void CollisionListener::initCollisionMaps()
{
	//Begin Contact map initialization
	m_beginContactCollisionMap[makeIntPair(FIXT_ID_PLAYER_SENSOR_GROUND, FIXT_ID_FLOOR)] = &CollisionListener::playerSensorGroundFloor;
	m_beginContactCollisionMap[makeIntPair(FIXT_ID_FLOOR, FIXT_ID_PLAYER_SENSOR_GROUND)] = &CollisionListener::floorPlayerSensorGround;
	
	m_beginContactCollisionMap[makeIntPair(FIXT_ID_ENEMY_SENSOR, FIXT_ID_PLAYER)] = &CollisionListener::enemyHitPlayer;
	m_beginContactCollisionMap[makeIntPair(FIXT_ID_PLAYER, FIXT_ID_ENEMY_SENSOR)] = &CollisionListener::playerHitEnemy;

	m_beginContactCollisionMap[makeIntPair(FIXT_ID_PLAYER_PROJECTILE, FIXT_ID_FLOOR)] = &CollisionListener::projectileHitFloor;
	m_beginContactCollisionMap[makeIntPair(FIXT_ID_FLOOR, FIXT_ID_PLAYER_PROJECTILE)] = &CollisionListener::floorHitProjectile;

	m_beginContactCollisionMap[makeIntPair(FIXT_ID_PLAYER_PROJECTILE_SENSOR, FIXT_ID_ENEMY_SENSOR)] = &CollisionListener::playerProjectileEnemy;
	m_beginContactCollisionMap[makeIntPair(FIXT_ID_ENEMY_SENSOR, FIXT_ID_PLAYER_PROJECTILE_SENSOR)] = &CollisionListener::enemyPlayerProjectile;

	//End Contact map initialization
	m_endContactCollisionMap[makeIntPair(FIXT_ID_PLAYER_SENSOR_GROUND, FIXT_ID_FLOOR)] = &CollisionListener::playerSensorGroundFloorEnd;
	m_endContactCollisionMap[makeIntPair(FIXT_ID_FLOOR, FIXT_ID_PLAYER_SENSOR_GROUND)] = &CollisionListener::floorPlayerSensorGroundEnd;
}

std::pair<int, int> CollisionListener::makeIntPair(int p_lhs, int p_rhs)
{
	return std::pair<int, int>(p_lhs, p_rhs);
}

void CollisionListener::playerSensorGroundFloor(void* p_playerSensorGround, void* p_floor)
{
	IComponent* component = static_cast<GameObject*>(p_playerSensorGround)->getComponent("SensorComponent");
	static_cast<SensorComponent*>(component)->beginContact();
}

void CollisionListener::projectileHitFloor(void* p_projectileHit, void* p_floor)
{
	GameObject* gameObject = static_cast<GameObject*>(p_projectileHit);
	gameObject->removeMe();
}

void CollisionListener::enemyHitPlayer(void* p_enemy, void* p_player)
{
	GameObject* player = static_cast<GameObject*>(p_player);
	GameObject* enemy = static_cast<GameObject*>(p_enemy);

	DamageComponent* dmg = static_cast<DamageComponent*>(enemy->getComponent("DamageComponent"));
	HealthComponent* hp = static_cast<HealthComponent*>(player->getComponent("HealthComponent"));
	PlayerControllerComponent* pcc = dynamic_cast<PlayerControllerComponent*>(player->getComponent("PlayerControllerComponent"));
	
	if (pcc)
	{
		if (hp->canReceiveDamage())
		{
			pcc->hit();
		}
		hp->decreaseHealth(dmg->getDamage());
	}
}

void CollisionListener::playerProjectileEnemy(void* p_playerProjectile, void* p_enemy)
{
	GameObject* projectile = static_cast<GameObject*>(p_playerProjectile);
	GameObject* enemy = static_cast<GameObject*>(p_enemy);

	DamageComponent* dmg = static_cast<DamageComponent*>(projectile->getComponent("DamageComponent"));
	HealthComponent* hp = static_cast<HealthComponent*>(enemy->getComponent("HealthComponent"));
	hp->decreaseHealth(dmg->getDamage());
	projectile->removeMe();
}


void CollisionListener::playerSensorGroundFloorEnd(void* p_playerSensorGround, void* p_floor)
{
	IComponent* component = static_cast<GameObject*>(p_playerSensorGround)->getComponent("SensorComponent");
	static_cast<SensorComponent*>(component)->endContact();
}